package org.me.marble;

/**
*
* @author tungi
*/

public class Geometry{

    public static boolean isPartOfTriangle(Vector point,Vector a,Vector b,Vector c,Vector normal){
        //check if the point is on the plane with normal vector equatation
        float d=normal.getX()*(point.getX()-a.getX())+
                normal.getY()*(point.getY()-a.getY())+
                normal.getZ()*(point.getZ()-a.getZ());
        d=MyMath.makeRound(d,2);
        if(d==0.00f){
            Vector x,y,z,d1,d2,d3;
            x=Vector.Minus(c,a);
            y=Vector.Minus(b,c);
            z=Vector.Minus(a,b);
            d1=Vector.Minus(point,a);
            d2=Vector.Minus(point,c);
            d3=Vector.Minus(point,b);

            double angle_x_d1=Math.acos(Geometry.getCosAngle(x,d1));
            double angle_y_d2=Math.acos(Geometry.getCosAngle(y,d2));
            double angle_z_d3=Math.acos(Geometry.getCosAngle(z,d3));

            double angle_x_z=Math.PI-Math.acos(Geometry.getCosAngle(x,z));
            double angle_x_y=Math.PI-Math.acos(Geometry.getCosAngle(x,y));
            double angle_y_z=Math.PI-Math.acos(Geometry.getCosAngle(y,z));

            if(angle_x_d1<=angle_x_z && angle_y_d2<=angle_x_y && angle_z_d3<=angle_y_z)
               return true;
            else
                return false;
        }
        return false;
    }

    public static Vector getPlaneNormal(Vector v1,Vector v2,Vector v3){
        //calculate the normal vector of the plane defined with the three
        //points got as parameter
        Vector ret=new Vector();
        ret.setX((v1.getY()-v2.getY())*(v1.getZ()-v3.getZ())
                    -(v1.getZ()-v2.getZ())*(v1.getY()-v3.getY()));
        ret.setY((v1.getZ()-v2.getZ())*(v1.getX()-v3.getX())
                    -(v1.getX()-v2.getX())*(v1.getZ()-v3.getZ()));
        ret.setZ((v1.getX()-v2.getX())*(v1.getY()-v3.getY())
                    -(v1.getY()-v2.getY())*(v1.getX()-v3.getX()));
        //to get a normal with up direction
        ret.set(-ret.getX(),-ret.getY(),-ret.getZ());
        ret.Normalize();
        return ret;
    }

    public static Vector getProjectionToPlane(Vector normal,Vector point0,Vector point){
        //get the projection of the point to the plane specified with the normal
    	//easier solution
    	return getPlaneToLineIntersection(normal,point0,new Vector(0,1,0),point);
    	//somthing wrong - need check
        /*float _d=normal.getX()*point0.getX()
                +normal.getY()*point0.getY()
                +normal.getZ()*point0.getZ();
        float t=(float)(normal.getX()*point.getX()+normal.getY()*point.getY()+normal.getZ()*point.getZ()-_d)
                /(float)(Math.pow(normal.getX(),2)+Math.pow(normal.getY(),2)+Math.pow(normal.getZ(),2));
        float _x=point.getX()-normal.getX()*t;
        float _y=point.getY()-normal.getY()*t;
        float _z=point.getZ()-normal.getZ()*t;
        return new Vector(_x,_y,_z);*/
    }

    public static double getCosAngle(Vector v1,Vector v2){
        //get the angle between to vectors
        return (v1.getX()*v2.getX()+v1.getY()*v2.getY()+v1.getZ()*v2.getZ())/
               (Math.sqrt(Math.pow(v1.getX(),2)+Math.pow(v1.getY(),2)+Math.pow(v1.getZ(),2))*
                Math.sqrt(Math.pow(v2.getX(),2)+Math.pow(v2.getY(),2)+Math.pow(v2.getZ(),2)));
    }

    public static Vector rotateVector(double _angle,Vector vector,Vector normal){
        //rotate vector with the specified angle int radian
        float rad=vector.Length();//the radius is the length of the vector
        //then we get the vector with a circle equatation in 3D
        Vector v=Vector.Plus(Vector.Multiplication(vector,rad*Math.cos(_angle)),
                Vector.Multiplication(Vector.crossProduct(normal,vector),rad*Math.sin(_angle)));
        //update vector coordinates
        return v;
    }

    public static Vector getPlaneToLineIntersection(Vector plane_normal,
            Vector plane_point,Vector line_direction,Vector line_point)
                    throws ArithmeticException{
            float t=(plane_normal.getX()*(plane_point.getX()-line_point.getX())+
                     plane_normal.getY()*(plane_point.getY()-line_point.getY())+
                     plane_normal.getZ()*(plane_point.getZ()-line_point.getZ()))/
                    (plane_normal.getX()*line_direction.getX()+
                     plane_normal.getY()*line_direction.getY()+
                     plane_normal.getZ()*line_direction.getZ());
            return new Vector(line_point.getX()+line_direction.getX()*t,
                              line_point.getY()+line_direction.getY()*t,
                              line_point.getZ()+line_direction.getZ()*t);
    }

    public static Vector getLineToLineIntersection(Vector A,Vector B,Vector dirA,Vector dirB){
        Vector a=Vector.crossProduct(dirA,dirB);
        Vector b=Vector.crossProduct(Vector.Minus(B,A),dirB);
        //float t=b.Length()/a.Length();
        float t=0.0f;
        if(a.getX()!=0 && b.getX()!=0)
            t=b.getX()/a.getX();
        else if(a.getY()!=0 && b.getY()!=0)
            t=b.getY()/a.getY();
        else if(a.getZ()!=0 && b.getZ()!=0)
            t=b.getZ()/a.getZ();
        else
            return null;//the two lines are parallel
        return new Vector(A.getX()+t*dirA.getX(),
                          A.getY()+t*dirA.getY(),
                          A.getZ()+t*dirA.getZ());
    }

    public static boolean isPartOfSection(Vector A,Vector B,Vector point){
        if(A.getX()>=B.getX() && (point.getX()>A.getX() || point.getX()<B.getX()))
            return false;
        else if(A.getY()>=B.getY() && (point.getY()>A.getY() || point.getY()<B.getY()))
            return false;
        else if(A.getZ()>=B.getZ() && (point.getZ()>A.getZ() || point.getZ()<B.getZ()))
            return false;
        else if(A.getX()<=B.getX() && (point.getX()<A.getX() || point.getX()>B.getX()))
            return false;
        else if(A.getY()<=B.getY() && (point.getY()<A.getY() || point.getY()>B.getY()))
            return false;
        else if(A.getZ()<=B.getZ() && (point.getZ()<A.getZ() || point.getZ()>B.getZ()))
            return false;
        else
            return true;
    }
    
    public static float getPointLineDistance(Vector linePointA,Vector linePointB,Vector point){
    	return (Vector.crossProduct(
    			Vector.Minus(point, linePointA),Vector.Minus(point, linePointB))).Length()/
    			(Vector.Minus(linePointB, linePointA)).Length();
    }

//    public Vector getProjectionToLine(Vector point,String direction){
//        Vector v,dir;
//        dir=Vector.Minus(path.vertices.get(1),path.vertices.get(0));
//        v=rotateVector(Math.PI/2,dir,getNormalOfTriangle(true));
//        float t=(v.getY()*(path.vertices.get(1).getX()-point.getX())+
//                v.getX()*(path.vertices.get(1).getY()-point.getY())/
//            v.getY()*(path.vertices.get(1).getX()-path.vertices.get(0).getX())+
//                v.getX()*(path.vertices.get(1).getY()-path.vertices.get(0).getY()));
//        return new Vector(
//            path.vertices.get(0).getX()-t*(path.vertices.get(1).getX()-path.vertices.get(0).getX()),
//            path.vertices.get(0).getY()-t*(path.vertices.get(1).getY()-path.vertices.get(0).getY()),
//            path.vertices.get(0).getZ()-t*(path.vertices.get(1).getZ()-path.vertices.get(0).getZ()));
//    }

}